BehaviourEnableSwitcher
クラスがアクティブ化された時、指定したBehaviourクラスのEnableを自動で切り替える拡張機能です
Timeline 上から Audio Low Pass Filter の機能をOn/Off したくて作成。 (なんか他にやりようはありそうだけど…)
コード全部
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.UIElements;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Core.Common
{
/// <summary>
/// BehaviourクラスのEnableをスクリプトから切り替える
/// </summary>
[ExecuteAlways]
public class BehaviourEnableSwitcher : MonoBehaviour
{
/* Define & Class */
public enum ApplyType
{
Active, // OnEnable/OnDisable時に適用する
}
/* Public Field */
/* Private Field */
[SerializeField] private GameObject _targetGameObject;
[SerializeField] private ApplyType _applyType;
[SerializeField] private string _targetType;
private bool _isInitialized;
private List<Behaviour> _allComponents = new List<Behaviour>();
private int _index;
/* Property */
/* Public Method */
/* Pritvate Method */
private void UpdateTarget()
{
if (_targetGameObject == null)
{
return;
}
_allComponents = _targetGameObject.GetComponents<Behaviour>().ToList();
_index = Mathf.Max(_allComponents.FindIndex(x => x.GetType().Name == _targetType), 0);
_isInitialized = true;
}
private void SetTargetEnable(bool isEnable)
{
if (!_isInitialized) return;
var component = _allComponents[_index];
component.enabled = isEnable;
}
/* Monobehaviour */
private void OnEnable()
{
if (_applyType == ApplyType.Active)
{
SetTargetEnable(true);
}
}
private void OnDisable()
{
if (_applyType == ApplyType.Active)
{
SetTargetEnable(false);
}
}
private void Awake()
{
UpdateTarget();
}
private void Start()
{
}
private void Update()
{
}
private void OnDestroy()
{
}
#if UNITY_EDITOR
[CustomEditor(typeof(BehaviourEnableSwitcher))]
public class ComponentEnableSwitcherEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var switcher = target as BehaviourEnableSwitcher;
switcher.UpdateTarget();
var root = new VisualElement();
// ターゲットとなるGameObject
var targetGameObjectProp = serializedObject.FindProperty(nameof(switcher._targetGameObject));
var targetTypeProp = serializedObject.FindProperty(nameof(switcher._targetType));
var targetGameObjectField = new PropertyField(targetGameObjectProp);
targetGameObjectField.RegisterValueChangeCallback(_ =>
{
// 値が更新されたらUpdateTargetメソッドを呼び出してリストを更新してもらう
switcher.UpdateTarget();
});
// 適用タイプ
var applyTypeProp = serializedObject.FindProperty(nameof(switcher._applyType));
var applyTypeField = new PropertyField(applyTypeProp);
// 文字列に変換して選択できるようにする
var allComponents = switcher._allComponents.Select(x => x.GetType().Name).ToList();
var componentMenu = new DropdownField("Target", allComponents, switcher._index);
componentMenu.RegisterValueChangedCallback(ev =>
{
switcher._index = allComponents.FindIndex(x => x == ev.newValue);
targetTypeProp.stringValue = ev.newValue;
serializedObject.ApplyModifiedProperties();
});
root.Add(targetGameObjectField);
root.Add(applyTypeField);
root.Add(componentMenu);
root.Bind(serializedObject);
return root;
}
}
#endif
}
}
Target Game Object には、切り替えたいComponentがついてるGameObjectを指定。 TargetでComponent名をリストから選択します
自分がアクティブ/非アクティブされるたびにTarget の Enable が切り替わる。
Timelineで使うときは Control Track を利用してアクティブ/非アクティブ 切り替えてもらって制御
「追記」 _targetGameObject に値を設定した直後、リストが生成されてもインスペクタに反映されない不具合見つけたので後日修正予定